// @flow

function square(a) {
  return a * a
}
square('100')


// 除了可以给函数的参数标记注解，还可以给变量标记注解
// 给变量num标记为number类型，如果修改成字符串类型，就会提示错误
let num: number = 100
num = '132'

// 存放 undefined 需要使用 void
let e: void = undefined

// 也可以给函数的返回值标记注解
// 如果没有返回值或者返回值类型不正确，都会提示
// 对于没有返回值的函数，应该将返回值的类型标记为void
function foo(): number {
  return '100'
}
function bar(): void {

}

// 第一种方法是使用 Array 类型
// 这种类型需要一个泛型参数，用来表示每一个元素的类型
// 下面这种就表示 全部由数字组成的数组
const arr1: Array<number> = [1, 2, 3, '']

// 元素类型后边跟一个数组的方括号，这种类型可以表示 全部由字符串组成的数组
const arr2: number[] = [1, '', null]

// 表示一个固定长度的数组，可以用类似数组字面量的方式表示
const arr3: [string, number] = ['', 100]

// 限制变量为对象类型，在类型注解里写 {}， 在{}里边添加具体的成员名称和对应的类型限制
// 如果需要某个成员是可选的，可以在这个成员后加一个 ?
const obj1: { foo?: string, bar: number } = { foo: 'string', bar: 123 }


// 很多时候会把对象当作键值对集合去使用，这种时候可以使用任意类型的键和任意类型的值
// 如果需要限制键和值的类型，可以使用类似索引器的语法来设置
// 以下这种表示这个对象可以添加任意多个属性，但是每个属性的键和值都必须为字符串
const obj3 ： { [string]: string } = {}
obj3.key1 = 'value1'
obj3.key2 = 'value2'


function foo(callback: (string, number) => void) {
  callback('string', 100)
}
foo(function (str, n) {
  // str --> string
  // n --> number
})



const a: 'foo' = 'foo'
const type: 'success' | 'warning' | 'danger' = 'success'

type StringOrNumber = string | number
const b: StringOrNumber = 'string' // 100

const num: ?number = null


// mixed 可以接收所有类型
function passMixed(value: mixed) {

}
